﻿using System.Security.Cryptography;
using System.Text;

namespace Simple.Common.Core.Utils
{
    public class RequestSign
    {
        /// <summary>
        /// 签名
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static void Sign<T>(T obj, string signKey, string signSecret)
        {
            var propertyApiKey = typeof(T).GetProperty("apiKey");
            if (propertyApiKey == null)
            {
                return;
            }
            propertyApiKey.SetValue(obj, signKey);

            var propertyTimeStamp = typeof(T).GetProperty("timeStamp");
            if (propertyTimeStamp == null)
            {
                return;
            }
            propertyTimeStamp.SetValue(obj, TimeUtil.GetTimeSpan());

            var propertySign = typeof(T).GetProperty("sign");
            if (propertySign == null)
            {
                return;
            }

            var data = $"{propertyApiKey.GetValue(obj)}{signSecret}{propertyTimeStamp.GetValue(obj)}";
            using (MD5 md5 = new MD5CryptoServiceProvider())
            {
                var res = md5.ComputeHash(Encoding.UTF8.GetBytes(data));
                StringBuilder sb = new StringBuilder(32);
                for (int i = 0; i < res.Length; i++)
                {
                    sb.Append(res[i].ToString("X2"));
                }
                var sign = sb.ToString();
                propertySign.SetValue(obj, sign);
            }
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool CheckSign<T>(T obj, string signKey, string signSecret, out string message)
        {
            message = null;

            var propertyApiKey = typeof(T).GetProperty("apiKey");
            if (propertyApiKey == null)
            {
                message = "无apiKey字段";
                return false;
            }
            var apiKey = propertyApiKey.GetValue(obj) as string;
            if (string.IsNullOrWhiteSpace(apiKey))
            {
                message = "apiKey不能为空";
                return false;
            }
            if (!apiKey.Equals(signKey))
            {
                message = "apiKey无效";
                return false;
            }

            var propertyTimeStamp = typeof(T).GetProperty("timeStamp");
            if (propertyTimeStamp == null)
            {
                message = "无timeStamp字段";
                return false;
            }
            var timeStamp = propertyTimeStamp.GetValue(obj) as string;
            if (string.IsNullOrWhiteSpace(timeStamp))
            {
                message = "timeStamp不能为空";
                return false;
            }

            var propertySign = typeof(T).GetProperty("sign");
            if (propertySign == null)
            {
                message = "sign";
                return false;
            }
            var sign = propertySign.GetValue(obj) as string;
            if (string.IsNullOrWhiteSpace(sign))
            {
                message = "sign不能为空";
                return false;
            }

            var data = $"{apiKey}{signSecret}{timeStamp}";
            var signCheck = string.Empty;
            using (MD5 md5 = new MD5CryptoServiceProvider())
            {
                var res = md5.ComputeHash(Encoding.UTF8.GetBytes(data));
                StringBuilder sb = new StringBuilder(32);
                for (int i = 0; i < res.Length; i++)
                {
                    sb.Append(res[i].ToString("X2"));
                }
                signCheck = sb.ToString();
                propertySign.SetValue(obj, sign);
            }

            if (!sign.Equals(signCheck))
            {
                message = "签名无效";
                return false;
            }

            return true;
        }
    }
}
